"""
路由配置
"""
import json
import os
import time
from flask import (render_template, current_app as app, jsonify, request, redirect, url_for, flash, session,
                   send_from_directory, abort)
from web3 import Web3
from web3.middleware import geth_poa_middleware
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import login_user, logout_user, login_required, current_user
from datetime import datetime

from werkzeug.utils import secure_filename

from .models import User, Data, DetectionNode
from . import db
from app.detector import Detector

# 创建监测器
detector = Detector(web3=Web3(Web3.HTTPProvider('http://127.0.0.1:8545')), app=app)  # 这里地址是默认的
# 定义上传文件保存目录
UPLOAD_FOLDER = './uploads'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

# 模型文件存放目录
MODEL_FOLDER = '../models'
app.config['MODEL_FOLDER'] = MODEL_FOLDER


@app.route('/')
def home():
    app.logger.debug('Home route accessed')
    return render_template('home.html')


@app.route('/connect', methods=['GET', 'POST'])
@login_required  # 只有登录后才能访问
def connect():
    global detector

    if request.method == 'POST':
        node_address = request.form['node_address']
        if not node_address:
            flash('Please provide a node address')
            return redirect(url_for('connect'))

        # 重新设置监测器
        w3 = Web3(Web3.HTTPProvider(node_address))
        w3.middleware_onion.inject(geth_poa_middleware, layer=0)
        detector.set_web3(w3)

        if not detector.web3.is_connected():
            flash('Unable to connect to the node')
            return redirect(url_for('connect'))

        session['node_address'] = node_address
        flash('Connected to node successfully')

        detector.init_nodes()
        # 开启监测任务
        # detector.start_check()
        # print('detect started')

        return redirect(url_for('nodes'))
    return render_template('connect.html')


@app.route('/nodes')
@login_required
def nodes():
    app.logger.debug('Nodes route accessed')
    return render_template('nodes.html')


@app.route('/data')
@login_required
def data():

    user_data = []
    user_home_directory = os.path.expanduser("~")

    target_directory = os.path.join(user_home_directory, ".fedchain", "pre_datas")
    if not os.path.exists(target_directory):
        # 如果目录不存在，则创建它
        os.makedirs(target_directory)

    processed_directory = os.path.join(user_home_directory, ".fedchain", "datas")
    if not os.path.exists(processed_directory):
        # 如果目录不存在，则创建它
        os.makedirs(processed_directory)

    files = os.listdir(target_directory)
    for file in files:
        dic = {}
        file_path = os.path.join(target_directory, file)
        if os.path.isfile(file_path):
            # 获取文件的保存时间
            file_time = os.path.getmtime(file_path)
            readable_time = time.ctime(file_time)
            dic['timestamp'] = readable_time
        dic['data_name'] = file
        dic['file_path'] = target_directory
        dic['status'] = 0
        user_data.append(dic)

    files = os.listdir(processed_directory)
    for file in files:
        dic = {}
        file_path = os.path.join(processed_directory, file)
        if os.path.isfile(file_path):
            # 获取文件的保存时间
            file_time = os.path.getmtime(file_path)
            readable_time = time.ctime(file_time)
            dic['timestamp'] = readable_time
        dic['data_name'] = file
        dic['file_path'] = processed_directory
        dic['status'] = 1
        user_data.append(dic)

    print(user_data , "+++++++++++++++++++")


    # user_data = Data.query.filter_by(server_address=detector.address).all()
    # print(user_data)
    return render_template('data.html', data=user_data)


@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        blockchain_address = request.form['blockchain_address']

        if not username or not password or not blockchain_address:
            flash('Please fill out all fields')
            return redirect(url_for('register'))

        hashed_password = generate_password_hash(password, method='pbkdf2:sha256')
        new_user = User(username=username, password_hash=hashed_password, blockchain_address=blockchain_address)
        db.session.add(new_user)
        db.session.commit()
        flash('User registered successfully!')
        return redirect(url_for('login'))
    return render_template('register.html')


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']

        user = User.query.filter_by(username=username).first()

        if not user or not check_password_hash(user.password_hash, password):
            flash('Invalid credentials')
            return redirect(url_for('login'))

        login_user(user)
        flash('Login successful')
        return redirect(url_for('home'))
    return render_template('login.html')


@app.route('/logout')
@login_required
def logout():
    detector.set_web3(web3=Web3(Web3.HTTPProvider("")))
    # detector.stop_check()
    session.pop('node_address', None)
    logout_user()
    flash('Logged out successfully')
    return redirect(url_for('home'))


@app.route('/api/nodes_status')
@login_required  # 只有登录后才能访问
def api_nodes_status():
    if 'node_address' not in session:
        return jsonify({"error": "Not connected to any node"}), 400

    if not detector.web3.is_connected():
        return jsonify({"error": "Unable to connect to the node"}), 500

    try:
        is_syncing = detector.web3.eth.syncing
        block_number = detector.web3.eth.block_number
        peer_count = detector.web3.net.peer_count
        node_version = detector.web3.client_version

        local_node_status = {
            "is_syncing": is_syncing,
            "block_number": block_number,
            "peer_count": peer_count,
            "node_version": node_version
        }
        detector.check_node_status()
        node_list = detector.get_node_status()
        # print(node_list)
        other_nodes_status = [{"address": node.node_address, "status": 'active' if node.is_active == 1 else 'inactive',
                               "last_update_time": node.last_updated}
                              for node in node_list]

        return jsonify({
            "local_node": local_node_status,
            "other_nodes": other_nodes_status
        })
    except Exception as e:
        return jsonify({"error": str(e)}), 500


@app.route('/heartbeat', methods=['POST'])
def heartbeat():
    global detector
    # if detector.task_started:
    data = request.get_json()
    node_address = data['node_address']
    if detector.check_node_exists(node_address) is None:
        node = DetectionNode(node_address=node_address, last_updated=datetime.utcnow(), is_active=True)
        db.session.add(node)
        db.session.commit()

    detector.nodes[node_address] = datetime.utcnow()
    print(f"received heartbeat from {node_address} at {detector.nodes[node_address]}")

    return jsonify({"status": "ok"})


@app.route('/upload', methods=['POST'])
def receive_data():
    # 检查请求中是否包含文件和数据
    if 'file' not in request.files or 'sensorData' not in request.form:
        return jsonify({"status": "error", "message": "Missing file or sensorData"}), 400

    file = request.files['file']
    sensor_data = request.form['sensorData']

    # 如果文件名为空，则返回错误
    if file.filename == '':
        return jsonify({"status": "error", "message": "No selected file"}), 400

    # 确保保存目录存在
    if not os.path.exists(app.config['UPLOAD_FOLDER']):
        os.makedirs(app.config['UPLOAD_FOLDER'])

    # 保存文件到指定目录
    file_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
    file.save(file_path)

    sensor_data_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename + ".json")
    with open(sensor_data_path, "w") as sensor_file:
        json.dump(json.loads(sensor_data), sensor_file)

    new_data = Data(server_address=detector.address, file_path=app.config['UPLOAD_FOLDER'], data_name=file.filename)
    db.session.add(new_data)
    db.session.commit()

    return jsonify({"status": "ok", "message": "File uploaded successfully"}), 200


@app.route('/download_model', methods=['GET'])
def download_model():
    return send_from_directory(app.config['MODEL_FOLDER'], 'yolov8n.onnx', as_attachment=True)
